﻿using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;

namespace Wicture.QPZS.EPC
{
    public class Compression
    {
        private static Random random = new Random();

        public static void CopyTo(Stream src, Stream dest)
        {
            byte[] bytes = new byte[4096];

            int cnt;

            while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
            {
                dest.Write(bytes, 0, cnt);
            }
        }

        public static byte[] Protect(byte[] source)
        {
            if (source == null && source.Length == 0)
            {
                return source;
            }

            var seed = (byte)random.Next(0, 99);
            var result = new byte[source.Length + 1];
            for (int i = 0; i < source.Length; i++)
            {
                result[i] = (byte)(source[i] - seed);
            }
            result[source.Length] = seed;
            return result;
        }

        public static byte[] Unprotect(byte[] source)
        {
            if (source == null && source.Length == 0)
            {
                return source;
            }

            var seed = source.Last();
            var result = new byte[source.Length - 1];
            for (int i = 0; i < source.Length - 1; i++)
            {
                result[i] = (byte)(source[i] + seed);
            }
            return result;
        }

        public static byte[] ZipAndProtect(object obj)
        {
            string str = null;
            if (obj is string)
            {
                str = obj as string;
            }
            else
            {
                str = JObject.FromObject(obj).ToString(Newtonsoft.Json.Formatting.None);
            }

            return Protect(Zip(str));
        }

        public static byte[] Zip(string str)
        {
            var bytes = Encoding.UTF8.GetBytes(str);

            using (var msi = new MemoryStream(bytes))
            using (var mso = new MemoryStream())
            {
                using (var gs = new GZipStream(mso, CompressionMode.Compress))
                {
                    CopyTo(msi, gs);
                }

                return mso.ToArray();
            }
        }

        public static string UnprotectAndUnzip(byte[] bytes)
        {
            var unprotectedBytes = Unprotect(bytes);
            return Unzip(unprotectedBytes);
        }

        public static string Unzip(byte[] bytes)
        {
            using (var msi = new MemoryStream(bytes))
            using (var mso = new MemoryStream())
            {
                using (var gs = new GZipStream(msi, CompressionMode.Decompress))
                {
                    CopyTo(gs, mso);
                }

                return Encoding.UTF8.GetString(mso.ToArray());
            }
        }
    }
}
